/*
 * Copyright (C) 2017 zhouyou(478319399@qq.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.shuyihui.rxhttp.request

import com.google.gson.reflect.TypeToken
import com.shuyihui.rxhttp.cache.model.CacheResult
import com.shuyihui.rxhttp.callback.CallBack
import com.shuyihui.rxhttp.callback.CallBackProxy
import com.shuyihui.rxhttp.func.*
import com.shuyihui.rxhttp.model.ApiResult
import com.shuyihui.rxhttp.subsciber.CallBackSubscriber
import com.shuyihui.rxhttp.transformer.HandleErrTransformer
import com.shuyihui.rxhttp.utils.RxUtil
import com.shuyihui.rxhttp.utils.Utils
import io.reactivex.Observable
import io.reactivex.ObservableTransformer
import io.reactivex.Observer
import io.reactivex.disposables.Disposable
import okhttp3.ResponseBody

/**
 *
 * 描述：自定义请求，例如你有自己的ApiService
 */
class CustomRequest : BaseRequest<CustomRequest>("") {
    public override fun build(): CustomRequest {
        return super.build()!!
    }

    /**
     * 创建api服务  可以支持自定义的api，默认使用BaseApiService,上层不用关心
     *
     * @param service 自定义的apiservice class
     */
    fun <T> create(service: Class<T>?): T {
        checkvalidate()
        return retrofit!!.create(service)
    }

    private fun checkvalidate() {
        Utils.checkNotNull(retrofit, "请先在调用build()才能使用")
    }

    /**
     * 调用call返回一个Observable<T>
     * 举例：如果你给的是一个Observable<ApiResult></ApiResult><AuthModel>> 那么返回的<T>是一个ApiResult<AuthModel>
    </AuthModel></T></AuthModel></T> */
    fun <T> call(observable: Observable<T?>): Observable<T> {
        checkvalidate()
        return observable.compose(RxUtil.io_main())
            .compose(HandleErrTransformer())
            .retryWhen(
                RetryExceptionFunc(
                    retryCount,
                    retryDelay.toLong(),
                    retryIncreaseDelay.toLong()
                )
            )
    }

    fun <T> call(observable: Observable<T>, callBack: CallBack<T?>?) {
        call(observable, CallBackSubscriber(context, callBack))
    }

    fun <R> call(observable: Observable<R>, subscriber: Observer<R?>) {
        observable.compose(RxUtil.io_main())
            .subscribe(subscriber)
    }

    /**
     * 调用call返回一个Observable,针对ApiResult的业务<T>
     * 举例：如果你给的是一个Observable<ApiResult></ApiResult><AuthModel>> 那么返回的<T>是AuthModel
    </T></AuthModel></T> */
    fun <T> apiCall(observable: Observable<ApiResult<T>?>): Observable<T> {
        checkvalidate()
        return observable
            .map(HandleFuc())
            .compose(RxUtil.io_main())
            .compose(HandleErrTransformer<T>())
            .retryWhen(
                RetryExceptionFunc(
                    retryCount,
                    retryDelay.toLong(),
                    retryIncreaseDelay.toLong()
                )
            )
    }

    fun <T> apiCall(observable: Observable<T?>, callBack: CallBack<T>?): Disposable {
        return call(observable, object : CallBackProxy<ApiResult<T>?, T>(callBack) {} )
    }

    fun <T> call(
        observable: Observable<T?>,
        proxy: CallBackProxy<out ApiResult<T>?, T>
    ): Disposable {
        val cacheobservable = build().toObservable(observable as Observable<ResponseBody>, proxy)
        return if (CacheResult::class.java != proxy.callBack!!.rawType) {
            cacheobservable!!.compose(ObservableTransformer<CacheResult<T>?, T> { upstream ->
                upstream.map(
                    CacheResultFunc()
                )
            }).subscribeWith(CallBackSubscriber(context, proxy.callBack))
        } else {
            cacheobservable!!.subscribeWith(
                CallBackSubscriber(
                    context,
                    proxy.callBack as CallBack<CacheResult<T>>
                )
            )
        }
    }

    private fun <T> toObservable(
        observable: Observable<out ResponseBody>,
        proxy: CallBackProxy<out ApiResult<T>?, T>?
    ): Observable<CacheResult<T>>? {
        val function: ApiResultFunc<T> = ApiResultFunc(proxy?.type ?: object :
            TypeToken<ResponseBody>() {}.type)
        return observable.map(function)
            .compose(if (isSyncRequest) RxUtil._main() else RxUtil._io_main<T>())
            .compose(rxCache!!.transformer(cacheMode, proxy!!.callBack!!.type))
            .retryWhen(
                RetryExceptionFunc(
                    retryCount,
                    retryDelay.toLong(),
                    retryIncreaseDelay.toLong()
                )
            ) as Observable<CacheResult<T>>
    }

    override fun generateRequest(): Observable<ResponseBody?>? {
        return null
    }
}

